package com.yami.shop.api.controller;


import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.mail.MailException;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.common.collect.Maps;
import com.yami.shop.bean.app.param.CheckRegisterSmsParam;
import com.yami.shop.bean.app.param.SendSmsParam;
import com.yami.shop.bean.app.param.UserPwdUpdateParam;
import com.yami.shop.bean.app.param.UserRegisterParam;
import com.yami.shop.bean.enums.SendType;
import com.yami.shop.bean.model.ChannelUserRelationRecord;
import com.yami.shop.bean.model.User;
import com.yami.shop.bean.param.UserAuthenticationParm;
import com.yami.shop.common.config.Constant;
import com.yami.shop.common.exception.YamiShopBindException;
import com.yami.shop.common.i18n.I18nMessage;
import com.yami.shop.common.response.ServerResponseEntity;
import com.yami.shop.common.util.*;
import com.yami.shop.config.ShopConfig;
import com.yami.shop.security.api.util.SecurityUtils;
import com.yami.shop.security.common.bo.UserInfoInTokenBO;
import com.yami.shop.security.common.enums.PortTypeEnum;
import com.yami.shop.security.common.enums.SysTypeEnum;
import com.yami.shop.security.common.manager.PasswordManager;
import com.yami.shop.security.common.manager.TokenStore;
import com.yami.shop.security.common.service.AppConnectService;
import com.yami.shop.security.common.vo.TokenInfoVO;
import com.yami.shop.service.*;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
import org.springframework.context.ApplicationContext;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * 用户信息
 *
 * @author LGH
 */
@RestController
@RequestMapping("/user")
@Tag(name = "用户注册相关接口")
@AllArgsConstructor
public class UserRegisterController {

    private final UserService userService;

    private final UserCancelService userCancelService;

    private final SmsLogService smsLogService;

    private final AppConnectService appConnectService;

    private final TokenStore tokenStore;

    private final PasswordEncoder passwordEncoder;

    private final PasswordManager passwordManager;

    public static final String CHECK_REGISTER_SMS_FLAG = "checkRegisterSmsFlag";

    public static final String CHECK_UPDATE_PWD_SMS_FLAG = "updatePwdSmsFlag";

    private final UserChainService userChainService;

    private final ShopConfig shopConfig;

    private final ChannelUserRelationRecordService channelUserRelationRecordService;

    private DataWebService dataWebService;

    private final ApplicationContext applicationContext;
    private final RemotePassManageService remotePassManageService;

    /**
     * 注册的头像昵称有几个值得注意的地方：
     * 1. 如果是微信公众号 or 小程序注册，在注册之前，也就是在进入页面之前，需要调用SocialLoginController 这里面的尝试登录的接口，如果可以登录就直接登录了。
     * 2. 关于发送验证码
     *    1) 手机号注册,要发送验证码
     * 3. 当注册成功的时候，已经返回token，相对来说，已经登录了
     */
    @Operation(summary="注册")
    @PostMapping("/register")
    public ServerResponseEntity<TokenInfoVO> register(@Valid @RequestBody UserRegisterParam userRegisterParam) {

        // 目前注册都是发验证码去注册的，看看有没有校验验证码成功的标识
        ServerResponseEntity<Void> validate = userService.validate(userRegisterParam, CHECK_REGISTER_SMS_FLAG + userRegisterParam.getCheckRegisterSmsFlag());
        if(!validate.isSuccess()){
            return ServerResponseEntity.showFailMsg(validate.getMsg());
        }
        // 正在进行申请注册
        if (userService.count(new LambdaQueryWrapper<User>().eq(User::getUserMobile, userRegisterParam.getMobile())) > 0) {
            // 该手机号已注册，无法重新注册
            return ServerResponseEntity.showFailMsg(I18nMessage.getMessage("yami.user.phone.exist"));
        }
        // 判断注销时间
        Boolean conformToRegister = userCancelService.isConformToRegister(userRegisterParam.getMobile(), "");
        if(!conformToRegister){
            return ServerResponseEntity.showFailMsg(I18nMessage.getMessage("yami.dtc.user.check.date"));
        }
        User user = appConnectService.registerAndBindUser(userRegisterParam.getMobile(), userRegisterParam.getPassword(), null);

        // 2. 登录

        UserInfoInTokenBO userInfoInTokenBO = new UserInfoInTokenBO();
        userInfoInTokenBO.setUserId(user.getUserId());
        userInfoInTokenBO.setSysType(SysTypeEnum.ORDINARY.value());
        userInfoInTokenBO.setIsAdmin(0);
        userInfoInTokenBO.setEnabled(true);

        // 免费活动发放
//        applicationContext.publishEvent(new NewcomerRewardsEvent(user.getUserId(),"7",null,"1"));

        return ServerResponseEntity.success(tokenStore.storeAndGetVo(userInfoInTokenBO));
    }



    @PutMapping("/sendRegisterSms")
    @Operation(summary =  "发送注册验证码", description = "发送注册验证码")
    public ServerResponseEntity<Void> register(@Valid @RequestBody SendSmsParam sendSmsParam) {
        if (userService.count(new LambdaQueryWrapper<User>().eq(User::getUserMobile, sendSmsParam.getMobile())) > 0) {
            // 该手机号已注册，无法重新注册
            return ServerResponseEntity.showFailMsg(I18nMessage.getMessage("yami.user.phone.exist"));
        }
        // 每个手机号每分钟只能发十个注册的验证码，免得接口被利用
        smsLogService.sendSms(SendType.REGISTER, sendSmsParam.getMobile(), sendSmsParam.getMobile(), Maps.newHashMap());
        return ServerResponseEntity.success();
    }

    @PutMapping("/checkRegisterSms")
    @Operation(summary =  "校验注册验证码", description = "校验验证码返回校验成功的标识")
    public ServerResponseEntity<String> register(@Valid @RequestBody CheckRegisterSmsParam checkRegisterSmsParam) {
        // 每个ip每分钟只能发十个注册的验证码，免得接口被利用
        if (!smsLogService.checkValidCode(checkRegisterSmsParam.getMobile(), checkRegisterSmsParam.getValidCode(), SendType.REGISTER)){
            // 验证码有误或已过期
            throw new YamiShopBindException("yami.user.code.error");
        }
        String checkRegisterSmsFlag = IdUtil.simpleUUID();
        RedisUtil.set(CHECK_REGISTER_SMS_FLAG + checkRegisterSmsFlag, checkRegisterSmsParam.getMobile(), 600);
        return ServerResponseEntity.success(checkRegisterSmsFlag);
    }

    @PutMapping("/sendBindSms")
    @Operation(summary =  "发送绑定验证码", description = "发送绑定验证码")
    public ServerResponseEntity<Void> bindSms(@Valid @RequestBody SendSmsParam sendSmsParam) {
        // 每个手机号每分钟只能发十个注册的验证码，免得接口被利用
        smsLogService.sendSms(SendType.VALID, sendSmsParam.getMobile(), sendSmsParam.getMobile(), Maps.newHashMap());
        return ServerResponseEntity.success();
    }


    @PutMapping("/checkUpdatePwdSms")
    @Operation(summary =  "修改密码校验验证码", description = "校验验证码返回校验成功的标识")
    public ServerResponseEntity<String> checkUpdatePwdSms(@RequestBody CheckRegisterSmsParam checkRegisterSmsParam) {
        boolean isCheckPass = false;
        if (Objects.nonNull(checkRegisterSmsParam) && Objects.nonNull(checkRegisterSmsParam.getMobile())) {
            Matcher m = Pattern.compile(PrincipalUtil.MOBILE_REGEXP).matcher(checkRegisterSmsParam.getMobile());
            isCheckPass = m.matches();
        }
        if (!isCheckPass) {
            return ServerResponseEntity.showFailMsg(I18nMessage.getMessage("yami.user.err.phone"));
        }

        User user = userService.getOne(new LambdaQueryWrapper<User>().eq(User::getUserMobile, checkRegisterSmsParam.getMobile()));
        if (user == null) {
            // 此用户不存在，请先注册
            return ServerResponseEntity.showFailMsg(I18nMessage.getMessage("yami.user.account.no.exist"));
        }
        if (!smsLogService.checkValidCode(user.getUserMobile(), checkRegisterSmsParam.getValidCode(), SendType.UPDATE_PASSWORD)) {
            // 验证码有误或已过期
            return ServerResponseEntity.showFailMsg(I18nMessage.getMessage("yami.user.code.error"));
        }
        String checkRegisterSmsFlag = IdUtil.simpleUUID();
        RedisUtil.set(CHECK_UPDATE_PWD_SMS_FLAG + checkRegisterSmsFlag, checkRegisterSmsParam.getMobile(), 600);
        return ServerResponseEntity.success(checkRegisterSmsFlag);
    }

    @PutMapping("/updatePwd")
    @Operation(summary =  "修改密码", description = "修改密码")
    public ServerResponseEntity<Void> updatePwd(@Valid @RequestBody UserPwdUpdateParam userPwdUpdateParam) {
        User user = userService.getOne(new LambdaQueryWrapper<User>().eq(User::getUserMobile, userPwdUpdateParam.getMobile()));
        if (user == null) {
            // 无法获取用户信息
            throw new YamiShopBindException("yami.user.no.exist");
        }
        UserRegisterParam registerParam = BeanUtil.map(userPwdUpdateParam, UserRegisterParam.class);
        // 看看有没有校验验证码成功的标识
        ServerResponseEntity<Void> validate = userService.validate(registerParam, CHECK_UPDATE_PWD_SMS_FLAG + userPwdUpdateParam.getCheckRegisterSmsFlag());
        if(!validate.isSuccess()){
            return ServerResponseEntity.showFailMsg(validate.getMsg());
        }
        String decryptPassword = passwordManager.decryptPassword(userPwdUpdateParam.getPassword());
        if (StrUtil.isBlank(decryptPassword)) {
            // 新密码不能为空
            return ServerResponseEntity.showFailMsg(I18nMessage.getMessage("yami.user.password.no.exist"));
        }
        if (StrUtil.equals(passwordEncoder.encode(decryptPassword), user.getLoginPassword())) {
            // 新密码不能与原密码相同!
            return ServerResponseEntity.showFailMsg(I18nMessage.getMessage("yami.user.password.check"));
        }
        user.setModifyTime(new Date());
        user.setLoginPassword(passwordEncoder.encode(decryptPassword));
        userService.updateById(user);
        tokenStore.deleteAllTokenUser(SysTypeEnum.ORDINARY.value().toString(), PortTypeEnum.DTC.value(),user.getUserId());
        return ServerResponseEntity.success();
    }

    /**
     * 腾讯实名暂时
     * @param
     * @return
     */
    @PostMapping("/ua/authenticationDtc")
    @Operation(summary =  "认证", description = "注册认证")
    public ServerResponseEntity<Void> authentication(@Valid @RequestBody UserAuthenticationParm userAuthenticationParm ) throws Exception {
        User userById = userService.getOne(new LambdaQueryWrapper<User>().eq(User::getUserId, userAuthenticationParm.getUserId()));
        if(ObjectUtil.isEmpty(userById)){
            throw new YamiShopBindException("yami.user.account.no.exist");
        }
        //判断身份证是否实名
        int count = (int) userService.count(new LambdaQueryWrapper<User>().eq(User::getIdNumber, userAuthenticationParm.getIdNumber()).eq(User::getRealName, userAuthenticationParm.getRealName()));
        if(count == 1 && userAuthenticationParm.getIdNumber().equals(userById.getIdNumber())){
            return ServerResponseEntity.success();
        }else if(count >0 && !userAuthenticationParm.getIdNumber().equals(userById.getIdNumber())){
            return ServerResponseEntity.showFailMsg(I18nMessage.getMessage("yami.user.other.authentication.isuser"));
        }
        //实名认证
        try {
            JSONObject jsonObject = CheckIdCardUtils.checkIdCard(userAuthenticationParm.getIdNumber(), userAuthenticationParm.getRealName());
            if(jsonObject.get("IdCardInfor")!=null){
                JSONObject inforData = JSONObject.parseObject(jsonObject.getString("IdCardInfor"));
                if(inforData!=null&&inforData.get("sex")!=null&&"男".equals(inforData.get("sex"))){
                    userById.setSex("M");
                }else if(inforData!=null&&inforData.get("sex")!=null&&"女".equals(inforData.get("sex"))){
                    userById.setSex("F");
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new YamiShopBindException(e.getMessage());
        }
        //修改数据库
        userById.setRealName(userAuthenticationParm.getRealName());
        userById.setIdNumber(userAuthenticationParm.getIdNumber());
        userService.updateById(userById);

        // 免费活动发放
//        applicationContext.publishEvent(new NewcomerRewardsEvent(userById.getUserId(),"8",null,"1"));
        return ServerResponseEntity.success();
    }

    /**
     * 不用
     * @param chainCode
     * @return
     */
    @GetMapping("/create/dtc/chainAddress")
    @Operation(summary =  "链上地址", description = "DTC链上地址")
    public ServerResponseEntity<Void> createChainAddress(@RequestParam String chainCode) {
        String userId = SecurityUtils.getUser().getUserId();
        User user = userService.getUserByUserId(userId);
        if (StringUtils.isEmpty(user.getIdNumber()) || StringUtils.isEmpty(user.getRealName())) {
            throw new YamiShopBindException("请先实名认证！");
        }
//        List<NftManage> list = nftManageService.list(new LambdaQueryWrapper<NftManage>().eq(NftManage::getType, 0).eq(NftManage::getStatus, 0).eq(NftManage::getCode, chainCode));
//        if (CollUtil.isEmpty(list) || list.size() > 1) {
//            throw new YamiShopBindException("链数据异常，不存在或存在多个");
//        }
        ChannelUserRelationRecord channelUserRelationRecord = channelUserRelationRecordService.getOne(new QueryWrapper<ChannelUserRelationRecord>()
                .lambda()
                .eq(ChannelUserRelationRecord::getUserId,userId)
                .eq(ChannelUserRelationRecord::getStatus,0)
                .eq(ChannelUserRelationRecord::getChannelCode,"dtc")
                .eq(ChannelUserRelationRecord::getChainCode, chainCode)
                .last("limit 1"));
        if(channelUserRelationRecord != null) {
            throw new YamiShopBindException("yami.channel.ischeck");
        }
        Map<String,String> obj = new HashMap<>();
        obj.put("chainCode", chainCode);
        obj.put("idNumber", user.getIdNumber());
        obj.put("mobile", user.getUserMobile());
        String url = shopConfig.getApiGatewayUrl() + "/nft/outapi/api/nftmint/generate?";
        JSONObject jsonObject = dataWebService.hutoolGetWebService(url, obj,null,null);
        if(jsonObject.getInteger("code")!= Constant.SUCCESS_CODE){
            throw new YamiShopBindException(jsonObject.getString("msg"));
        }
        JSONObject resObj = jsonObject.getJSONObject("data");
        String mnemonic = resObj.getString("mnemonic");
        String address = resObj.getString("address");
        ChannelUserRelationRecord record = ChannelUserRelationRecord.builder()
                .userId(userId).channelCode("dtc").chainCode(chainCode).address(address).mnemonic(mnemonic).status(0).createTime(new Date()).type("1").build();
        channelUserRelationRecordService.save(record);
        return ServerResponseEntity.success();
    }

    /**
     * chainCode 对应店铺必须有 添加链地址
     * @param hashMap
     * @return
     */
    @Operation(summary="远程注册")
    @PostMapping("/remoteRegister")
    public ServerResponseEntity<TokenInfoVO> remoteRegister(@Valid @RequestBody Map<String,Object> hashMap) {
//        Map<String,Object> hashMap = new HashMap<>();
        try {
            String chainCode = (String)hashMap.get("chainCode");
            String channelCode = (String)hashMap.get("channelCode");
            String callPhone = (String) hashMap.get("callPhone");
            String realName = (String) hashMap.get("realName");
            String idCard = (String) hashMap.get("idCard");
            if(StrUtil.isEmpty(chainCode) || StrUtil.isEmpty(channelCode) || StrUtil.isEmpty(callPhone) || StrUtil.isEmpty(realName) || StrUtil.isEmpty(idCard)) {
                return ServerResponseEntity.showFailMsg("参数不能为空");
            }
//            if(StrUtil.isEmpty(chainCode)){
//                return ServerResponseEntity.showFailMsg("参数异常");
//            }
//            RemotePassManage remotePassManage = remotePassManageService.getOne(new QueryWrapper<RemotePassManage>()
//                    .lambda().eq(RemotePassManage::getName, channelCode).last("limit 1"));
//            dataWebService.checkSign(jSONObject,hashMap,remotePassManage.getPassword());
            //商城注册账号和实名
            // 正在进行申请注册
            User user = null;
            List<User> list = userService.list(new LambdaQueryWrapper<User>().and(u-> u.eq(User::getUserMobile, callPhone).or().eq(User::getIdNumber, idCard)));
            if ( list.size() == 1) {
//                // 该手机号已注册，无法重新注册
//                return ServerResponseEntity.showFailMsg(I18nMessage.getMessage("yami.user.phone.exist"));
                user = list.get(0);
                if(StrUtil.isEmpty(user.getIdNumber())){
                    //实名
                    user.setRealName(realName);
                    user.setIdNumber(idCard);
                    userService.updateById(user);
                }
            }else if(list.size() > 1){
                List<User> collect = list.stream().filter(s -> idCard.equals(s.getIdNumber())).collect(Collectors.toList());
                if(collect.size()>0){
                    user = collect.get(0);
                }else{
                    user = list.get(0);
                    //实名
                    user.setRealName(realName);
                    user.setIdNumber(idCard);
                    userService.updateById(user);
                }
            }else if(list.size() == 0){
                user = appConnectService.registerAndBindUser(callPhone, null, null);
                //实名
                user.setRealName(realName);
                user.setIdNumber(idCard);
                userService.updateById(user);
            }
            //添加链上资产
            ChannelUserRelationRecord channelUserRelationRecord = channelUserRelationRecordService.getOne(new QueryWrapper<ChannelUserRelationRecord>()
                    .lambda()
                    .eq(ChannelUserRelationRecord::getUserId,user.getUserId())
                    .eq(ChannelUserRelationRecord::getStatus,0)
                    .eq(ChannelUserRelationRecord::getChannelCode, channelCode)
                    .eq(ChannelUserRelationRecord::getChainCode, chainCode)
                    .last("limit 1"));
            if(channelUserRelationRecord == null) {
                Map<String,String> obj = new HashMap<>();
                obj.put("chainCode", chainCode);
                obj.put("idNumber", user.getIdNumber());
                obj.put("mobile", user.getUserMobile());
                String url = shopConfig.getApiGatewayUrl() + "/nft/outapi/api/nftmint/generate?";
                JSONObject jsonObject = dataWebService.hutoolGetWebService(url, obj,null,null);
                if(jsonObject.getInteger("code")!= Constant.SUCCESS_CODE){
                    throw new YamiShopBindException(jsonObject.getString("msg"));
                }
                JSONObject resObj = jsonObject.getJSONObject("data");
                String mnemonic = resObj.getString("mnemonic");
                String address = resObj.getString("address");
                ChannelUserRelationRecord record = ChannelUserRelationRecord.builder()
                        .userId(user.getUserId()).channelUserId(user.getUserId()).channelCode(channelCode).chainCode(chainCode).address(address).mnemonic(mnemonic).status(0).createTime(new Date()).type("1").build();
                channelUserRelationRecordService.save(record);
            }
            return ServerResponseEntity.success();
        } catch (MailException e) {
            e.printStackTrace();
            return ServerResponseEntity.showFailMsg("注册异常");
        }catch (Exception e){
            return ServerResponseEntity.showFailMsg(e.getMessage());
        }
    }
}
